Skip to content

AIR CLI Integration: hyperlink Run ID/Experiment, MLflow run name, and i/L in air list - #6260

Merged
riddhibhagwat-db merged 2 commits into
air-clifrom
air-list-picker-aircli
Aug 14, 2026
Merged

AIR CLI Integration: hyperlink Run ID/Experiment, MLflow run name, and i/L in air list#6260
riddhibhagwat-db merged 2 commits into
air-clifrom
air-list-picker-aircli

Conversation

@riddhibhagwat-db

@riddhibhagwat-db riddhibhagwat-db commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Enriches the interactive air list picker toward the Python AIR CLI.

Changes

  1. Run ID and Experiment cells are OSC-8 hyperlinks — Run ID → the job-run page, Experiment → the MLflow experiment page — alongside the existing MLflow link. Underlined only when a link is actually present; piped / NO_COLOR output stays plain (no escapes).
  2. MLflow column shows the MLflow run name (with a …<id8> fallback) instead of a truncated …/runs/<id> URL. Reuses the existing fetchMLflowRunName / mlflowRunLabel; the resolved label is cached for terminal runs.
  3. i and L/l open an in-TUI scrollable panei shows run details (the same styled view as air get), L shows a logs snapshot (bubbles/viewport). esc returns to the list with the cursor preserved. enter still opens MLflow in the browser.

Notes

  • The logs snapshot is a one-shot tail (staticView), so viewing an active run’s logs can’t hang the pane waiting on a live stream.
  • The detail/logs panes render captured (renderRunText / fetchLogs) output; since the capture target isn’t a TTY they render in the ASCII profile (text and box borders intact, no color). A forced-color pane is a possible follow-up.
  • Reuses air-cli’s existing mlflowExperimentURL for the experiment link (no ?o=, consistent with the other ML URLs) rather than adding a parallel helper.

Tests

  • Unit: hyperlink rendering (asserts the OSC-8 escape is present with links, absent without), i → detail-mode transition, detail-pane content + esc back, run-name label.
  • Acceptance (air list): the MLflow column now shows the run name; golden regenerated. Full air unit + acceptance suite, go vet, gofmt, and golangci-lint all pass.

This pull request and its description were written by Isaac.
Screenshot 2026-08-13 at 9 38 35 PM

…add i/L in `air list`

Enriches the interactive `air list` picker toward the Python CLI:

- Run ID and Experiment cells are now OSC-8 hyperlinks (job-run page and
  MLflow experiment page, org-pinned), alongside the existing MLflow link.
  Underlined only when actually linked; piped/NO_COLOR output stays plain.
- The MLflow column shows the MLflow run name (with a …<id8> fallback)
  instead of a truncated URL, reusing fetchMLflowRunName/mlflowRunLabel.
  Cached for terminal runs.
- `i` opens a scrollable run-details pane and `L`/`l` a logs snapshot pane
  (bubbles/viewport); `esc` returns to the list. `enter` still opens MLflow.
  The logs snapshot is a one-shot tail (staticView) so an active run can't
  hang the pane.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 1177284

Run: 31654553958

Env 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 291 1105 3:20
💚​ aws windows 4 4 293 1103 2:56
💚​ azure linux 4 4 290 1105 3:20
💚​ azure windows 4 4 292 1103 3:06
💚​ gcp linux 1 5 291 1105 3:23
💚​ gcp windows 1 5 293 1103 3:29
8 interesting tests: 4 RECOVERED, 4 SKIP
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R
Top 1 slowest tests (at least 2 minutes):
duration env testname
2:04 gcp windows TestAccept

@riddhibhagwat-db riddhibhagwat-db changed the title experimental/air: hyperlink Run ID/Experiment, MLflow run name, and i/L in air list AIR CLI Integration: hyperlink Run ID/Experiment, MLflow run name, and i/L in air list Aug 13, 2026
Comment thread experimental/air/cmd/list_tui_test.go Outdated
m := next.(listModel)

// A resolved detailMsg fills the pane.
next, _ = m.Update(detailMsg{title: "Run details", body: "hello from the detail pane"})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you hardcoded "Run details" but elsewhere it's "Run Details". Can you keep the capitalization consistent?

Comment thread experimental/air/cmd/list_tui.go Outdated
if m.fetcher != nil && len(m.rows) > 0 {
m.mode = modeDetail
m.detailLoading = true
m.detailTitle = "Logs snapshot"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you set the title to "Logs snapshot" but elsewhere it's "Logs Snapshot". Let's keep the capitalization consistent.

Comment on lines +195 to +206
case detailMsg:
m.detailLoading = false
if msg.err != nil {
m.detailContent = fmt.Sprintf("Error: %v", msg.err)
} else {
m.detailContent = msg.body
}
m.detailTitle = msg.title
m.viewport.SetContent(m.detailContent)
m.viewport.GotoTop()
m.mode = modeDetail
return m, nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an issue Claude found:
i/L set mode = modeDetail and kick off an async GetRun/logs fetch. If the user hits esc back to the list before that fetch resolves, this handler unconditionally flips mode back to modeDetail, snapping them out of the list into a pane they already dismissed. Suggest dropping the result if we're no longer in detail mode:

Suggested change
case detailMsg:
m.detailLoading = false
if msg.err != nil {
m.detailContent = fmt.Sprintf("Error: %v", msg.err)
} else {
m.detailContent = msg.body
}
m.detailTitle = msg.title
m.viewport.SetContent(m.detailContent)
m.viewport.GotoTop()
m.mode = modeDetail
return m, nil
case detailMsg:
// If the user pressed esc back to the list before async fetch
// completes, drop the late result.
if m.mode != modeDetail {
return m, nil
}
m.detailLoading = false
if msg.err != nil {
m.detailContent = fmt.Sprintf("Error: %v", msg.err)
} else {
m.detailContent = msg.body
}
m.detailTitle = msg.title
m.viewport.SetContent(m.detailContent)
m.viewport.GotoTop()
return m, nil

…detail results

- Use title case ("Run Details" / "Logs Snapshot") for the pane title in both
  the loading and resolved states (was mixed case).
- Drop a detailMsg that arrives after the user has escaped back to the list, so
  a slow GetRun/logs fetch can't snap them back into a pane they dismissed.

Co-authored-by: Isaac
@riddhibhagwat-db
riddhibhagwat-db merged commit 2471e2c into air-cli Aug 14, 2026
9 checks passed
@riddhibhagwat-db
riddhibhagwat-db deleted the air-list-picker-aircli branch August 14, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants